/*
 *  Copyright 2008 The MITRE Corporation (http://www.mitre.org/). All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */



package org.mitre.lattice.graph;

import java.awt.Point;
import java.awt.geom.Rectangle2D;
import java.util.Vector;

import org.jgraph.JGraph;
import org.jgraph.graph.CellView;
import org.jgraph.graph.VertexView;
import org.jgraph.layout.SugiyamaLayoutAlgorithm;
/**
 * Arranges the nodes with the Sugiyama Layout Algorithm.<br>
 *
 * <a href="http://plg.uwaterloo.ca/~itbowman/CS746G/Notes/Sugiyama1981_MVU/">
 *  Link to the algorithm</a>
 *
 */

public class MraldLayoutAlgorithm extends SugiyamaLayoutAlgorithm {

	/**
	 * Implementation.
	 *
	 * First of all the Algorithm searches the roots from the
	 * Graph. Starting from this roots the Algorithm creates
	 * levels and stores them in the member <code>levels</code>.
	 * The Member levels contains Vector Objects and the Vector per level
	 * contains Cell Wrapper Objects. After that the Algorithm
	 * tries to solve the edge crosses from level to level and
	 * goes top down and bottom up. After minimization of the
	 * edge crosses the algorithm moves each node to its
	 * bary center. Last but not Least the method draws the Graph.
	 *
	 * @see LayoutAlgorithm
	 *
	 */
	public void run(JGraph jgraph, Object[] cells, int step) {
		CellView[] selectedCellViews =
			jgraph.getGraphLayoutCache().getMapping(cells);


		/*  The Algorithm distributes the nodes on a grid.
		 *  For this grid you can configure the horizontal spacing.
		 *  This field specifies the configured value
		 *
		 */

		Rectangle2D maxBounds = new Rectangle2D.Double();
		for (int i = 0; i < selectedCellViews.length; i++) {
			// Add vertex to list
			if (selectedCellViews[i] instanceof VertexView) {
				// Fetch Bounds
				Rectangle2D bounds = selectedCellViews[i].getBounds();
				// Update Maximum
				if (bounds != null)
					maxBounds.setFrame(0, 0,
							Math.max(bounds.getWidth(), maxBounds.getWidth()),
							Math.max(bounds.getHeight(), maxBounds.getHeight()));
			}
		}

		if (spacing.x == 0)
			spacing.x = (int) (2 * maxBounds.getWidth());

		/*  The Algorithm distributes the nodes on a grid.
		 *  For this grid you can configure the vertical spacing.
		 *  This field specifies the configured value
		 *
		 */

		if (spacing.y == 0)
			spacing.y = (int) (2*maxBounds.getHeight()); // (jgraph.getGridSize()*6);

		// search all roots
		Vector roots = searchRoots(jgraph, selectedCellViews);

		// return if no root found
		if (roots.size() == 0)
			return;

		// create levels
		Vector levels = fillLevels(jgraph, selectedCellViews, roots);

		// solves the edge crosses
		solveEdgeCrosses(jgraph, levels);

		// move all nodes into the barycenter
		moveToBarycenter(jgraph, selectedCellViews, levels);

		Point min = findMinimumAndSpacing(selectedCellViews, spacing);

		// draw the graph in the window
		drawGraph(jgraph, levels, min, spacing);

		// clean temp values from the nodes / cells
		// the clean up was made in drawGraph
		cleanUp(jgraph, selectedCellViews);
	}

	/** Cleanup method to remove settings
	 *
	 */
	protected void cleanUp(JGraph jgraph, CellView[] cells)
	{
		jgraph.getGraphLayoutCache().remove(jgraph.getRoots());
		jgraph.getGraphLayoutCache().refresh(cells, true);

	}

}

